const {ResponseController} = require("./responseController")
const Util = require("../util")
const logger = require("../logger")
const Room = require("../room");
const Message = require("../message");
const {Member} = require("../member");

class RequestController {

    constructor(client, req, roomMap) {
        this._roomMap = roomMap;
        this._meesageTimestamp = Date.now()
        this._heartbeatTime = 10000;
        this._req = req;
        this._client = client;
        this._peerId = Util.getuuidv4();
        this._responseController = new ResponseController();
        new Promise(async (resolve, reject) => {
            const {status, message} = await this.parseReq()
            if (status) resolve()
            else reject(message)
        }).then(() => {
            console.log("解析成功")
            this.initResponseController()
            this._responseController.authorization()
            this._client.on('message', (message) => this.message(message))
            this._client.on('close', () => this.close())
            this.heartbeat()
        }).catch((reason) => {
            logger.info(reason)
            this._client.close()
        })
    }

    /**
     * 心跳检测 10 秒没心跳关闭
     */
    heartbeat() {
        if (this._heartbeatInterval !== undefined) clearTimeout(this._heartbeatInterval)
        this._heartbeatInterval = setTimeout(() => {
            this.close()
            logger.info("heartbeat close");
        }, this._heartbeatTime)
    }



    initResponseController() {
        this._responseController.setClient(this._client).setPeerId(this._peerId).setRoomId(this._roomId);
    }


    async parseReq() {
        try {
            this._roomId = (this._req.url.substring(1, this._req.url.length).split('/'))[1]

            if (this._roomId.trim().length <= 0) {
                return {status: false, message: "roomId is empty"}
            }
            if (this._roomMap.get(this._roomId) === undefined) {
                this._room = new Room(this._roomId)
                await this._roomMap.set(this._roomId, this._room);
                await this._roomMap.initRoom(this._roomId)
            }
            this._room = this._roomMap.get(this._roomId)
            return {status: true, message: "success"}
        } catch (error) {
            logger.info(error)
            return {status: false, message: error}
        }

    }


    async message(message) {
        try {
            const decoder = Message.decoder(message);
            switch (decoder.type) {
                case Message.msgType.join:
                    this.heartbeat()
                    this.join()
                    break;
                case Message.msgType.createTransport:
                    this.heartbeat()
                    await this.createTransport(decoder);
                    break;
                case Message.msgType.connectWebRtcTransport:
                    this.heartbeat()
                    await this.connectWebrtcTransport(decoder)
                    break
                case Message.msgType.producer:
                    this.heartbeat()
                    await this.producer(decoder)
                    break;
                case Message.msgType.pauseProducer:
                    this.heartbeat()
                    await this.pauseProducer(decoder)
                    break;
                case Message.msgType.resumeProducer:
                    this.heartbeat()
                    await this.resumeProducer(decoder)
                    break;
                case Message.msgType.ping:
                    await this.ping();
                    break;
                case Message.msgType.memberList:
                    await this.memberList();
                    break;
                case Message.msgType.sendMessageToPeerId:
                    await this.sendMessageToPeerId(decoder);
                    break;
            }
        } catch (error) {
            logger.info(error)
            this._responseController.error(error)
            this.close()
        }
    }

    notifiedMemberList() {
        this._room.getMembers().forEach((allMember, id) => {
            const memberList = []
            this._room.filterMembers(allMember.peerId).forEach((member, id2) => {
                memberList.push(member.peerId)
            })
            this._responseController.notifiedMessage(allMember.client, {
                memberList: memberList
            })
        })
    }

    memberList() {
        const memberList = []
        this._room.filterMembers(this._peerId).forEach((member, id) => {
            memberList.push(member.peerId)
        })
        this._responseController.memberList({
            memberList: memberList
        })
    }

    /**
     * 发送数据给其他 peerId
     * @param decoder  data 格式 : data:{ peerId: "", message: ""}
     */
    sendMessageToPeerId(decoder) {
        const peerId = decoder.data.peerId
        const member = this._room.getMember(peerId)
        if (member !== undefined) {
            this._responseController.memberReceiveMessage(member.client, decoder.data.message)
        }
    }

    ping(){
        this.heartbeat()
        this._responseController.pong()
    }

    close() {
        try{
            if (this._heartbeatInterval !== undefined) clearTimeout(this._heartbeatInterval)
            const memberDestroy = this._member.destroy()
            this._room.removeMember(this._peerId)
            for (const [id, member] of this._room.getMembers()) {
                memberDestroy.produce.forEach((producerId) => { //遍历 用户的消费者，对应就关闭
                    member.getTransport().forEach((transportInfo, transportId) => {
                        transportInfo.getConsumer().forEach((consume, consumeId) => {
                            if (consume.producerId === producerId) {
                                memberDestroy.consume.push(consumeId)
                                consume.close()
                                transportInfo.removeConsumer(consumeId)
                            }
                        })
                    })
                })
                member.client.send(Message.encoder(Message.msgType.memberDestroy, {
                    ...memberDestroy,
                    peerId: this._peerId
                }))
            }
        }catch (e) {
            logger.info(e)
        }

        this._client.close()

    }


    /**
     * 加入，发送 媒体信息
     */
    join() {
        this._member = new Member(this._peerId, this._client)
        this._room.pushMember(this._peerId, this._member)
        this._room.getRouterCapabilities()
        const rtpCapabilities = this._room.getRouterCapabilities()
        this._responseController.join({
            rtpCapabilities
        })
        this.notifiedMemberList()
    }

    /**
     * 创建 transport
     * @param decoder
     * @returns {Promise<void>}
     */
    async createTransport(decoder) {
        let appData
        const isConsumer = decoder.data.isConsumer
        if (isConsumer) {
            appData = {producing: false, consuming: true}
        } else {
            appData = {producing: true, consuming: false}
        }

        const transportInfo = await this._room.createTransport(this._peerId, decoder.data.numStreams, appData)
        const transport = transportInfo.transport
        //rtpCapabilities = decoder.data.rtpCapabilities

        this._responseController.createTransport({
            id: transport.id,
            iceParameters: transport.iceParameters,
            iceCandidates: transport.iceCandidates,
            dtlsParameters: transport.dtlsParameters,
            sctpParameters: transport.sctpParameters,
            isConsumer: isConsumer
        })
        if (isConsumer)
            await this.createTransportSendNewConsumer(transportInfo)
    }

    /**
     * 连接 transport
     * @param decoder
     * @returns {Promise<void>}
     */
    async connectWebrtcTransport(decoder) {
        const transportId = decoder.data.transportId

        const connect = await this._member.connectTransport(transportId, decoder.data.dtlsParameters)
        this._responseController.connectWebRtcTransport({
            isConsumer: decoder.data.isConsumer,
            transportId: transportId
        })
    }

    /**
     * 创建生产者
     * @param decoder
     * @returns {Promise<void>}
     */
    async producer(decoder) {
        const transportId = decoder.data.transportId

        const produce = await this._member.getTransportById(transportId).createProducer(decoder.data.kind, decoder.data.rtpParameters, decoder.data.appData);
        this._responseController.producer({
            producerId: produce.id,
            kind: produce.kind
        })
        await this.producerSendNewConsumer(produce)
    }


    /**
     * 创建 消费者
     * @param transportInfo
     * @param producer
     * @param peerId
     * @returns {Promise<{peerId, transportId, kind, rtpParameters: *, id, producerId, type, appData}>}
     */
    async createConsumer(transportInfo, producer, peerId) {
        const consumer = await transportInfo.createConsumer(producer, this._room.getRouterCapabilities()) //根据producer 创建自己 consume
        return {
            id: consumer.id,
            producerId: producer.id,
            kind: consumer.kind,
            transportId: transportInfo.transport.id,
            peerId: peerId,
            rtpParameters: consumer.rtpParameters,
            type: consumer.type,
            appData: consumer.appData,
            pause: producer.paused
        }
    }


    /**
     * @param decoder
     * @returns {Promise<void>}
     */
    async pauseProducer(decoder) {
        const producerId = decoder.data.producerId;
        const producer = this._member.getProducer(producerId)
        producer.pause()
        await this.updateConsumerStatus(producerId, Message.msgType.pauseProducer)
    }


    /**
     * 恢复 consumer
     * @param decoder
     * @returns {Promise<void>}
     */

    async resumeProducer(decoder) {
        const producerId = decoder.data.producerId;
        const producer = this._member.getProducer(producerId)
        producer.resume()
        await this.updateConsumerStatus(producerId, Message.msgType.resumeProducer)
    }


    /**
     * 获取 transport 回调函数
     * @param callback
     * @returns {Promise<void>}
     */
    async getTransportCallback(callback) {
        this._room.filterMembers(this._peerId).forEach((member, peerId) => {
            member.getTransport().forEach(async (transportInfo, transportId) => { // 获取
                callback(member, transportInfo)
            })
        })
    }

    /**
     * 开始 推送数据 时候 为 其他 用户 创建newConsumer
     * @param producer
     * @returns {Promise<void>}
     */
    async producerSendNewConsumer(producer) {
        await this.getTransportCallback(async (member, transportInfo) => {
            if (transportInfo.transport.appData.consuming) {
                try {
                    this._responseController.newConsumer(await this.createConsumer(transportInfo, producer, this._peerId), member.client)
                } catch (error) {
                    logger.info(error)
                    this._responseController.error(error)
                    this.close()
                }
            }
        })
    }

    /**
     * 创建 transport 时候 为 自己创建 consumer
     * @returns {Promise<void>}
     */
    async createTransportSendNewConsumer(createTransportInfo) {
        await this.getTransportCallback((member, transportInfo) => {
            transportInfo.getProducer().forEach(async (producer, producerId) => { //获取transport 中 produce
                try {
                    this._responseController.newConsumer(await this.createConsumer(createTransportInfo, producer, member.peerId), this._client)
                } catch (error) {
                    logger.info(error)
                }

            })
        })
    }

    /**
     * 修改 consumer 状态
     * @param producerId
     * @param messageType
     * @returns {Promise<void>}
     */
    async updateConsumerStatus(producerId, messageType) {
        await this.getTransportCallback((member, transportInfo) => {
            transportInfo.getConsumer().forEach((consumer, consumeId) => {
                if (consumer.producerId === producerId) {
                    if (messageType === Message.msgType.pauseProducer) {
                        consumer.pause()
                        this._responseController.pauseConsumer({
                            peerId: this._peerId,
                            producerId: producerId,
                            consumerId: consumer.id
                        }, member.client)
                    }
                    if (messageType === Message.msgType.resumeProducer) {
                        consumer.resume()
                        this._responseController.resumeConsumer({
                            peerId: this._peerId,
                            producerId: producerId,
                            consumerId: consumer.id
                        }, member.client)
                    }
                }
            })
        })
    }
}

module.exports = {RequestController}
